#pragma once
#include "Sock.hpp"
#include "Err.hpp"
#include "Log.hpp"
#include "Epoller.hpp"
#include <iostream>
#include <string>
#include <functional>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <sys/epoll.h>

class EpollServer
{
    const static int gnum = 64;
    const static int defaultport = 8888;
    using func_t = std::function<std::string(const std::string &)>;

public:
    EpollServer(func_t func, int port = defaultport)
        : port_(defaultport),
          func_(func)
    {
    }
    void InitServer()
    {
        listensockfd_.Socket();
        listensockfd_.Bind(port_);
        listensockfd_.Listen();
        epoll_.Create();
    }
    void Start()
    {
        int flag = true;
        // 1.将监听套接字存入epoll中
        flag = epoll_.AddEvent(listensockfd_.Fd(), EPOLLIN);
        assert(flag);
        // 2. 获取读的事件是否发生
        while (true)
        {
            int n = epoll_.Wait(envs_, gnum, -1);
            if (n > 0)
            {
                logMessage(Info, "有%d件事件就绪了", n);
                HandlerEvent(n);
            }
            else if (n == 0)
            {
                logMessage(Info, "epoll wait timeout ...");
                continue;
            }
            else
            {
                logMessage(Error, "epoll wait error:%s [code:%d]", strerror(errno), errno);
                break;
            }
        }
    }
    void HandlerEvent(int n)
    {
        for (int i = 0; i < n; ++i)
        {
            // 获取文件描述符
            int fd = envs_[i].data.fd;
            // 获取事件
            uint32_t events = envs_[i].events;
            // 如果是读事件
            if (events & EPOLLIN) // 有读事件就绪
            {
                // 如果是listen套接字有读事件就绪
                if (fd == listensockfd_.Fd()) // listen套接字有读事件就绪
                {
                    Accepter();
                }
                // 如果是接受上来的套接字有读事件就绪
                else // 接受上来的套接字有读事件就绪
                {
                    ServerIO(fd);
                }
            }
            // 其它事件TODO
            else // 其它事件TODO
            {
            }
        }
    }
    void Accepter()
    {
        // 1.接受客户的sockfd
        std::string clientip;
        uint16_t clientport;
        int sockfd = listensockfd_.Accept(&clientip, &clientport);
        if (sockfd < 0)
            return;
        logMessage(Debug, "%s:%d 已经连上了服务器了", clientip.c_str(), clientport);
        // 2. 尝试添加到epoll管理中
        bool flag = epoll_.AddEvent(sockfd, EPOLLIN);
        if (!flag) // 存储失败，无法继续为客户进行服务
        {
            close(sockfd);
            logMessage(Warning, "接受客户失败：clientip:%s ,clientport:%d, sockfd:%d", clientip.c_str(), clientport, sockfd);
        }
        else // 存储成功
        {
            logMessage(Info, "接受客户成功：clientip:%s ,clientport:%d, sockfd:%d", clientip.c_str(), clientport, sockfd);
        }
    }
    void ServerIO(int fd)
    {
        char buffer[1024];
        ssize_t n = recv(fd, buffer, sizeof(buffer), 0);
        if (n > 0)
        {
            buffer[n]=0;
            std::cout<<"client#"<<buffer<<std::endl;
            std::string respons=func_(buffer);
            //BUG
            send(fd,respons.c_str(),respons.size(),0);
        }
        else
        {
            if (n == 0)
                logMessage(Info, "client quit ...");
            else
                logMessage(Warning, "recv error, client quit ...");
            // 在处理异常的时候，先从epoll中移除，然后再关闭
            epoll_.DelEvent(fd);
            close(fd);
        }
    }

    void DebugPrint()
    {
    }

    ~EpollServer()
    {
        listensockfd_.Close();
        epoll_.Close();
    }

private:
    uint16_t port_;
    Sock listensockfd_;
    struct epoll_event envs_[gnum];
    Epoll epoll_;
    func_t func_;
};
